main.c

					
/*
 * main.c
 *
 * Created: 17.03.2022 22:27:16
 * Author : bohdan
 */ 
#include "main.h"

#include <avr/io.h>
#include <xc.h>
#include <avr/interrupt.h>		// defines sei();
#include <stdio.h>
#include <stdint.h>				// defines data types like uint8_t
#include <stdlib.h>				// defines malloc();
#include <util/delay.h>			// allows usage of _delay_ms_();
#include <math.h>

#include "UART_avr.h"
#include "Ring_buffer.h"
#include "Tim_ATmega328p.h"
#include "PIN_avr.h"
#include "Encoder.h"

void Calc_Sinus(sinus_t* Sinus, uint16_t Freq, uint16_t Samp_Rate);

#define BUFFER_SIZE (uint16_t)1024
#define MAX_SAMPLES 25400UL
#define SAMPLE_RATE 6250			// Hz
#define UART_BAUD_RATE 57600UL		// 38400 bits/sec - maximal amounts of transferred bytes per second: 4800 bytes, 57600 - 7200 bytes/sec
#define TIM2_PSK 1					// Prescaler of the TIM2

uint8_t tim1_i; 
uint16_t tim2_i;
uint16_t sinus_i;
uint8_t UART_bubble;
uint8_t Current_PWM_Rate = 50;

pin_t led = {_PB, 5};				// Arduino pin 13
pin_t pwm_sound = {_PB, 3};			// timer 2 compA pin, Arduino pin 11
pin_t pwm_volume = {_PB, 1};		// timer 1 compA pin, Arduino pin 9
pin_t enc_a = {_PD, 3};				// Arduino 3
pin_t enc_b = {_PD, 4};				// Arduino 4

uint8_t Transfer_byte;
uint16_t TIM2_update_rate;			// Defines how often will the TIM2 for sound creation update the value of OC2RA

encoder_t Encoder;
queue_t Ring_buffer;
status_t Status;
sinus_t Sinus_array;

char str[30];  // String buffer for transferring to the COM Port

int main(void)
{
	sei();
	
	TIM2_update_rate = (uint16_t)(F_CPU/TIM2_PSK/256/SAMPLE_RATE);
	
	pin_mode(pwm_sound, OUTPUT);
	pin_mode(led, OUTPUT);
	pin_mode(pwm_volume, OUTPUT);	
	
	init_buffer(&Ring_buffer, BUFFER_SIZE); // Memory allocation for the buffer
	UART0_start(UART_BAUD_RATE);
	
	init_encoder(&Encoder, enc_a, enc_b);
	
	TIMER_Set(TIM1, PWM, Current_PWM_Rate);				// Task of the TIM1 - PWM generation for volume control. 50 = Duty Cycle
	
	TIMER_Set(TIM2, TIM2_A_SOUND_PWM, 0);	// Task of the TIM2 - PWM generation for Sound playing
	Calc_Sinus(&Sinus_array, 440, SAMPLE_RATE);
	
	sprintf(str, "MCU_OK, UPD RATE = %d\n", TIM2_update_rate);
	print_str(str);
	sprintf(str, "F_PWM = %d Hz\n", (int)(F_CPU/(unsigned long)TIM2_PSK/(unsigned long)256));
	print_str(str);
	
    while (1) 
    {
		/******************************* SETTING THE VOLUME VALUE *******************************/ 
		if(Encoder.ticks_RIGHT > 0)
		{
			if(Current_PWM_Rate < 100)
			{
				Current_PWM_Rate++;
				TIM1_Set_PWM(Current_PWM_Rate);
			}
				//Current_PWM_Rate = pwm_write_perc(PWM_Out, Current_PWM_Rate + DIFFERENTIAL_VAL); // increasing the PWM with every tick
			Encoder.ticks_RIGHT--;
			sprintf(str, "OCR1A = %d\tPWM = %d\n", OCR1A, Current_PWM_Rate);
			print_str(str);
			//print_enc_state(&Encoder);
		}
		
		if(Encoder.ticks_LEFT > 0)
		{
			//Current_PWM_Rate = pwm_write_perc(PWM_Out, 0 > (Current_PWM_Rate - DIFFERENTIAL_VAL) ? 0 : (Current_PWM_Rate - DIFFERENTIAL_VAL)); // decreasing the PWM with every tick. if its looped over 0, write 0
			if(Current_PWM_Rate > 0)
			{
				Current_PWM_Rate--;
				TIM1_Set_PWM(Current_PWM_Rate);
			}
			Encoder.ticks_LEFT--;
			sprintf(str, "OCR1A = %d\tPWM = %d\n", OCR1A, Current_PWM_Rate);
			print_str(str);
			//Serial_print_enc_state(&Encoder);
		}

		
		if(Status.RX_INT)
		{
			Status.RX_INT = 0;
			if(put_sample(&Ring_buffer, &UART_bubble, 1) == LOW)			// Buffer Overflow
			{
				//Status.BUFF_OVF = 1;
				pin_write(led, HIGH);
			}
			else   // debug, putting successfully 
			{
				//UART_TR(Bubble);
				pin_write(led, LOW);
			}
			
		}
		
		if(Status.TIM2_UPDATE)			// *********************************SOUND, SET SAMPLE
		{
			
			Status.TIM2_UPDATE = 0;
			
			/*************************** SINUS GENERATOR ***************************/
			/*OCR2A = Sinus_array.arr[sinus_i];
			
			sinus_i++;
			
			if(sinus_i >= Sinus_array.size_)
			{
				sinus_i = 0;
				//pin_toggle(led);
			}*/
			
			
			/*************************** RECEVING SOUND ***************************/
			uint8_t sound_duty_cycle;
			
			//
			
			//pin_toggle(led);
			
			if((Ring_buffer.bytes_written != 0)) // if there is data to read from the buffer
			{

				if(get_sample(&Ring_buffer, &sound_duty_cycle, 1) == HIGH)
				{
					OCR2A = sound_duty_cycle;
					//UART_TR(OCR2A);		//
					//pin_write(led, LOW);
				}
				//else    // The buffer is empty
				//{
					//OCR2A = 0;
					//pin_write(led, HIGH);
				//}
			}
		}
			
    }
}

/**************** Creating the PWM Signal for playing sound ***************/
ISR(TIMER2_OVF_vect) // Sound generation. After the amount of time according to the sample rate - put a new value to the OCR2A Register
{
	/* Interrupt freq F_CPU/PRESCALER/256 = 62500 Hz
	 * SAMPLE_RATE is a value in Hz = Recording Frequency
	 * then changing the PWM Value each F_CPU/PRESCALER/256/SAMPLE_RATE = TIM2_update_rate
	 */
	tim2_i++;
	if(tim2_i >= TIM2_update_rate)
	{
		Status.TIM2_UPDATE = 1;
		tim2_i = 0;
	}
}

/**************** Generation of Volume PWM. Updating the Encoder State ***************/
ISR(TIMER1_OVF_vect)  // Interrupt period (psc = 1) = 15625 Hz
{
	tim1_i++;
	if(tim1_i >= 15)
	{
		update_enc_state(&Encoder);
		tim1_i = 0;
	}
}

/* UART RX Interrupt */
/* Putting the received data into the Ring Buffer */
 
ISR(USART_RX_vect)
{
	UART_bubble = UART_REC();
	Status.RX_INT = 1;
}

void Calc_Sinus(sinus_t* Sinus, uint16_t Freq, uint16_t Samp_Rate)
{
	//uint8_t* ptr;
	
	//static long dt_us;                          // Variable to store time points for sinus calculation
	Sinus->size_ = F_CPU / (TIM2_PSK * (1+0x00ff)) / Freq / TIM2_update_rate;            // Calculate Size of the array to be created
	Sinus->freq = Freq;
	
	sprintf(str, "\nSIN Size = %d;\n", Sinus->size_);
	print_str(str);
	
	Sinus->arr = (uint8_t*)malloc(Sinus->size_);            // Allocate memory for the array
	
	for(uint16_t i = 0; i < Sinus->size_; i++)
	{
		Sinus->arr[i] = (sin(2*M_PI*i/Sinus->size_) + 1)*127; //(127 + (int)120*sin(2*M_PI*Freq*(dt_us/1e6))); // Fill in the array cells
		sprintf(str, "%d\n", Sinus->arr[i]);
		print_str(str);
	}
}